/*
 * ***** BEGIN LICENSE BLOCK *****
 * This file is part of "myWiWall".
 * Copyright (c) 2007 CRP Henri Tudor and contributors.
 * All rights reserved.
 *
 * "myWiWall" is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 
 * "myWiWall" is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with "myWiWall"; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * ***** END LICENSE BLOCK *****
 */
 
//function Widget(id, title, height, width, eventDispatcher, dragManager)
function Widget(options, eventDispatcher, dragManager)
{
	this.preferences 				= new Object();
	this.id							= options.id;
	this.title 						= options.title;
	this.defaultTitle 				= options.title;
	this.defaultHeight 				= options.height || 150;
	this.defaultWidth 				= options.width || 300;
	this.eventDispatcher 			= eventDispatcher;
	this.useAuthentication 			= (options.useAuthentication == undefined) ? false : options.useAuthentication;
	this.dragManager 				= dragManager;
	this.registeredWithDragManager 	= false;
	this.minimized					= options.minimized;
	this.maximized					= !options.minimized;
	
	// W3C : Core APIs and Events : Widget interface attributes
	this.identifier					= options.id;
	this.authorName					= options.authorName || null;	
	this.authorEmail				= options.authorEmail || null;	
	this.authorURL					= options.authorURL || null;
	this.name						= options.title || null;			
	this.description				= options.description || null;	
	this.version					= options.version || null;	// TODO Implement Widget.version. 11th January 2008 : not yet specified in Packaging and Configuration spec.
	this.locale						= options.locale || null;
	this.height 					= options.height || 150;
	this.width 						= options.width || 300;
	this.onbeforeupdate				= options.onbeforeupdate;	// TODO Try to understand what is widget.onbeforeupdate.
	this.onafterupdate				= options.onafterupdate;	// TODO Try to understand what is widget.onafterupdate.
	this.currentIcon				= options.icon || null;		// TODO Implement Widget.currentIcon.
	
	// Because we only support one icon for the moment, that does not
	// make really sense at this time ...
	// TODO support more than one icon as in the Packaging and Configuration Specification.
	this.icons						= new Array();
	if (this.currentIcon)
		this.icons.push(this.currentIcon);
	
	/* this value is modified accordingly in devEnv.js */
	var l = window.getPortalBaseURI();
	if (l.indexOf('#') > -1)
		l = l.substr(0, l.length - 1);
	
	this.contentProxyUrl = l + 'proxy/contentProxy.php';
	this.relativePath = l + 'widgets/' + this.id + '/';
	
	// Please note that the third parameter is for internal use only.
	// For widget developpers, the setPreferenceForKey method should only
	// appears with the two first parameters.
	this.setPreferenceForKey = function(preference, key, persist) {
		this.preferences[preference] = key;
		var data = new Object();
		data['widgetId'] = this.id;
		data[preference] = key;
		
		if (persist == undefined || (persist && persist == true))
		{
			/* synchronize preferences with server */
			$.ajax({
				type: "GET",
				url: "../../index.php/engine/updatePreferences",
				data: data,
				dataType: 'html',
				success: function(text){
					/* possibility to add an event when the preferences have been saved */
				},
				error: function(xhr, msg, type){
					/* this will probably happen when tested locally */
				}
			});
		}
	};
	
	// W3C : Core APIs and events : Widget interface methods
	this.setPreference = function(key, value) {
		this.setPreferenceForKey(value, key);
	}
	
	this.getPreference = function(key) {
		return this.preferenceForKey(key);
	}
	
	this.hasFeature = function(url) {
		// Not enough information in the spec to implement it.
		return false;
	}
	
	this.setIcon = function(src) {
		// That does not make any sense since we only support
		// a unique default icon. However, if in the future we choose
		// to implement the custom icons collection as in the Packacking
		// and Configuration spec, the following code lines will remain compliant.
		for (i in this.icons)
		{
			if (this.icons[i].src == src)
			{
				this.currentIcon = this.icons[i];
				widgetFactory.widgets[this.id].setIcon(src);
				return;
			}
		}
		
		// Nothing found ... Maybe src is a URI pointing on something compliant on the
		// web. Let's assume the resource will always be available... That's what every lambda
		// developper will actually do ... That's bad, but I'm stuck ! If the resource cannot be
		// found, I don't really know what the browser will do... for sure, diplaying something
		// awful (but useful) and destroy the look and feel of my GUI. If I perform an XHR in order
		// to look if the resource is available (and with a compliant content type), I may not be sure that 
		// the next request performed by the browser will succeed... and I am going back to my first hypothesis \O/ Hourriii !
		// Thus, I will just have a look the src, and if dereferencable (TODO Check for a real URI ...
		// a day) let's set it as the icon (hope the resource is really any kind of image :D).
		
		if (src && typeof src == 'string' && src.substr(0,7) == 'http://')
		{
			// Ok, we have to create a new WidgetIcon instance and set it as currentIcon's value.
			// However, I don't think that adding this new WidgetIcon instance to the icons array
			// is a good thing because the icon, as a web resource, does not really belongs to the widget.
			var widgetIconParams = {
				src: src,
				active:	true 
			};
			
			this.currentIcon = new WidgetIcon(widgetIconParams);
			widgetFactory.widgets[this.id].setIcon(src);
		}
	}
	
	this.openURL = function(url) {
		window.open(url, '_blank');
	}
	
	this.show = function() {
		widgetFactory.widgets[this.id].showHide();
	}
	
	this.hide = function () {
		widgetFactory.widgets[this.id].showHide();
	}
	
	this.getAttention = function () {
		widgetFactory.widgets[this.id].setAttention();
	}
	
	this.showNotification = function (title, message, callback) {
		// Not enough information in the specification to implement the method.
	}
	
	// -- End of W3C : Core APIs and events : Widget interface methods
	
	
	// Palette Widget API extension.
	this.preferenceForKey = function(preference) {
		if (this.preferences[preference])
			return this.preferences[preference];
		else
			return null;
	}

	this.httpGet = function(url, data, callback, errorCallback)
	{
		this.ajax({
			url: url,
			type: 'GET',
			data: data,
			callback: callback,
			error: errorCallback
		});
	}
	
	this.httpGetJSON = function(url, data, callback, errorCallback)
	{
		this.ajax({
			url: url,
			type: 'GET',
			dataType: 'json',
			data: data,
			callback: callback,
			error: errorCallback
		});
	}
	
	// contentType is optional. If data is an object, contentType value is not taken into account
	this.httpPost = function(url, data, callback, contentType, errorCallback)
	{
		params = {
			url: url,
			type: 'POST',
			data: data,
			callback: callback,
			error: errorCallback
		};
		if (contentType != undefined && contentType != 'application/x-www-form-urlencoded') {
			params.contentType = contentType;
		}
		this.ajax(params);
	}
	
	// contentType is optional. If data is an object, contentType value is not taken into account
	this.httpPut = function(url, data, callback, contentType)
	{
		params = {
			url: url,
			type: 'PUT',
			data: data,
			callback: callback
		};
		if (contentType != undefined && contentType != 'application/x-www-form-urlencoded') {
			params.contentType = contentType;
		}
		this.ajax(params);
	}
	
	this.httpDelete = function(url, data, callback)
	{
		this.ajax({
			url: url,
			type: 'DELETE',
			data: data,
			callback: callback
		});
	}
	
	this.setHttpCredentials = function(username, password)
	{
		this.httpCredentials = {'user': username, 'password': password};
	}
	
	this.ajax = function(options)
	{
		var request = new Object();
		headers = new Object();		
		
		if(options.type) {
			request.type = options.type;
		}

		if(options.dataType) {
			request.dataType = options.dataType;
		}

		if(options.data) {
			if(typeof options.data == 'object') {
				request.processData = true;
			} else {
				request.processData = false;
				if(options.contentType) {
					request.contentType = options.contentType;
				} 				
			}
		} else {
			options.data = new Object();
		}
		
		if(options.callback) {
			request.success = options.callback;
		}
		
		if(options.error)
		{
			request.error = options.error;
		}
		
		if (options.url.substr(0, 7) != 'http://') {
			/* request a local file */
			request.data = options.data;
			request.url = this.relativePath + options.url;
		}
		else
		{
			/* request a remote file */
			request.url = this.contentProxyUrl;
			request.data = options.data;
			headers['X-Forward-Url'] = options.url;
		
			if (request.type == 'GET' && request.data)
			{
				request.data['mwwrand'] = Math.floor(Math.random() * 100000000001);
			}
		
			if (!request.processData && request.type != 'GET' && options.contentType) {
					headers['Content-type'] = options.contentType;
			}			
		}

		// method emulation
		if (request.type != 'POST' && request.type != 'GET') {
			headers['X-Method-Emulation'] = request.type;
			request.type = 'POST';
		}	
		
		// Widget Authentication will overide httpCredentials if activated.
		if (this.useAuthentication) {
			headers['X-Widget-Authentication'] = 'enabled';
			headers['X-Widget-Id'] = this.id;
		}
		else
		{
			headers['X-Widget-Authentication'] = 'disabled';
			
			if (this.httpCredentials) {
				var tok = this.httpCredentials.user + ':' + this.httpCredentials.password;
				var hash = Base64.encode(tok);
				var auth = "Basic " + hash;
				headers['Authorization'] = auth;
			}
		}

		// test if headers object is empty
		headersCount = 0;
		for (i in headers) {
			headersCount++;
		}

		if (headersCount != 0) {
			request.beforeSend = function(req) {			
				for (i in headers) {
					v = headers[i];
					req.setRequestHeader(i, v);
				}
			}			
		}
		
		// By default, 15 seconds is the maximum time before a request timeout.
		// We can discuss it :D ... or make it configurable.
		request.timeout = 15000;
		request.async = true;

		$.ajax(request);
	}
	
	this.setContentProxy = function(path)
	{
		this.contentProxyUrl = path;
	}

	this.setTitle = function(title)
	{
		this.title = title;
		widgetFactory.widgets[this.id].updateTitle(title);
	}

	this.getTitle = function()
	{
		return this.title;
	}

	this.setHeight = function(height)
	{
		this.height = height;
		widgetFactory.widgets[this.id].updateHeight(height);		
	}

	this.getHeight = function()
	{
		return this.height;
	}
	
	this.getDefaultHeight = function()
	{
		return this.defaultHeight;
	}
	
	this.getDefaultTitle = function()
	{
		return this.defaultTitle;
	}
}

Widget.prototype.addWidgetEventListener = function(eventType, eventHandler, acceptedSource) 
{
	this.eventDispatcher.addWidgetEventListener(this.id, eventType, eventHandler, acceptedSource);	
}

Widget.prototype.removeWidgetEventListener = function(eventType, source) 
{
	this.eventDispatcher.removeWidgetEventListener(this.id, eventType, source);
}
	
Widget.prototype.fireWidgetEvent = function(target, eventType, data) 
{
	this.eventDispatcher.fireWidgetEvent(this.id, eventType, data, target);
}

Widget.prototype.enableAuthentication = function ()
{
	this.useAuthentication = true;
}